//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <winhack.h>
#include <elasys_server.h>
#include <elapi.h>
#include <driver.h>
#include <stdlib.h>
#include <string.h>

#include <hook.h>

class NotiCenter : public Hook, public CDeviceDriver
{
public:
    NotiCenter(int MaxItem);

    ~NotiCenter();

    CARAPI Read(
        /* [in] */ Int64 u64Offset,
        /* [in] */ Int32 bytesToRead,
        /* [out] */ MemoryBuf * pBuffer,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Write(
        /* [in] */ Int64 u64Offset,
        /* [in] */ const MemoryBuf & buffer,
        /* [out] */ Int32 * pBytesWritten,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Control(
        /* [in] */ Handle32 nControlCode,
        /* [in] */ const MemoryBuf & inBuffer,
        /* [out] */ MemoryBuf * pOutBuffer,
        /* [out] */ IEvent * * ppCompletionEvent);

    // It's Maybe have no use for the keyboard driver.
    virtual void Dispose() {}
    HANDLE  m_hMutex;
};

NotiCenter::NotiCenter(int MaxItem) : Hook( MaxItem )
{
    return ;
}

NotiCenter::~NotiCenter()
{
    if (m_hMutex) {
        CloseHandle(m_hMutex);
        m_hMutex = NULL;
    }
    return ;
}

ECode NotiCenter::Read(
    /* [in] */ Int64 u64Offset,
    /* [in] */ Int32 bytesToRead,
    /* [out] */ MemoryBuf * pBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

ECode NotiCenter::Write(
    /* [in] */ Int64 u64Offset,
    /* [in] */ const MemoryBuf & buffer,
    /* [out] */ Int32 * pBytesWritten,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

ECode NotiCenter::Control(
    /* [in] */ Handle32 nControlCode,
    /* [in] */ const MemoryBuf & inBuffer,
    /* [out] */ MemoryBuf * pOutBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    int eType = (int)nControlCode & 0xffff;
    int nCode = (int)nControlCode >> 16;
    EventNotify(eType, nCode, inBuffer.GetPayload());
    return NOERROR;
}

static NotiCenter g_NotiCenter(EVENT_MAX);

int AddNotify(int EventType, const void *pNotiProc)
{
    g_NotiCenter.Set(EventType, pNotiProc);
    return 0;
}

void NotifyByIsr(int eType, int nCode, void *pParam)
{
    g_NotiCenter.CallNext(eType, nCode, pParam);
    return;
}

void EventNotify(int eType, int nCode, void *pParam)
{
    WaitForSingleObject(g_NotiCenter.m_hMutex, (DWORD)INFINITE);
#if defined(_DEBUG)
//    if (eType != EVENT_TIMER)
//        printf("Ev[%d]: nCode(%d) %x\n", eType, nCode, pParam?*(int *)pParam:0);
#endif
    g_NotiCenter.CallNext(eType, nCode, pParam);
    ReleaseMutex(g_NotiCenter.m_hMutex);
    return;
}

EXTERN IDeviceDriver * CDECL CreateNotiCenter(uint_t uDeviceNo, void *pvParameter)
{
    g_NotiCenter.m_hMutex = CreateMutexW(NULL, FALSE, NULL);
    //printf("Create NotiCenter %x\n", &g_NotiCenter);
    return (IDeviceDriver *)&g_NotiCenter;
}

/////////////////////////////////////////////////////////////////////
//system internal hook for user extern, id >= 16
EXTERN_C int __stdcall _SysSetHook(int hHook, const void *pHookProc)
{
    if (hHook < 16) return -1;
//    printf("SetHook (%d) %x\n", hHook, pHookProc);
    g_NotiCenter.Set(hHook, pHookProc);
    return 0;
}

EXTERN_C void __stdcall _SysCallNextHook(int hHook, int nCode, void *pParam)
{
//    printf("Ho[%d]: nCode(%d) %x\n", hHook, nCode, pParam?*(int *)pParam:0);
    g_NotiCenter.CallNext(hHook, nCode, pParam);
}

EXTERN_C void __stdcall _SysUnhook(int hHook)
{
//    printf("Unhook (%d) %x\n", hHook);
    g_NotiCenter.Set(hHook, NULL);
}
